home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / clipper / nfsrc21.zip / NWSEM.PRG < prev    next >
Text File  |  1992-10-17  |  18KB  |  574 lines

  1. /*
  2.  * File......: NWSEM.PRG
  3.  * Author....: Glenn Scott
  4.  * CIS ID....: 71620,1521
  5.  * Date......: $Date:   17 Oct 1992 16:28:22  $
  6.  * Revision..: $Revision:   1.4  $
  7.  * Log file..: $Logfile:   C:/nanfor/src/nwsem.prv  $
  8.  * 
  9.  * This is an original work by Glenn Scott and is placed in the
  10.  * public domain.
  11.  *
  12.  * Modification history:
  13.  * ---------------------
  14.  *
  15.  * $Log:   C:/nanfor/src/nwsem.prv  $
  16.  * 
  17.  *    Rev 1.4   17 Oct 1992 16:28:22   GLENN
  18.  * Leo cleaned up documentation blocks.
  19.  * 
  20.  *    Rev 1.3   08 Oct 1992 01:37:34   GLENN
  21.  * Added ft_nwsemUnlock() to complement ft_nwsemlock().  Modified
  22.  * the calling procedure for ft_nwsemlock() but it shouldn't break any
  23.  * existing code, although I doubt anyone's using it.
  24.  * 
  25.  * 
  26.  *    Rev 1.2   17 Aug 1991 16:11:46   GLENN
  27.  * Oops, I forgot to comment out some test code.
  28.  * 
  29.  *    Rev 1.1   15 Aug 1991 23:05:34   GLENN
  30.  * Forest Belt proofread/edited/cleaned up doc
  31.  * 
  32.  *    Rev 1.0   28 Jun 1991 00:44:14   GLENN
  33.  * Initial revision.
  34.  *
  35.  */
  36.  
  37.  
  38. // --------------------------------------------------------------
  39. //    Semaphore Package for Novell NetWare
  40. // --------------------------------------------------------------
  41.  
  42.  
  43. #include "ftint86.ch"
  44.  
  45. #define INT21    33
  46.  
  47. #xcommand DEFAULT <v1> TO <x1> [, <vN> TO <xN> ];
  48.       => IIF((<v1>)=NIL,<v1>:=<x1>,NIL) [; IF((<vN>)=NIL,<vN>:=<xN>,NIL)]
  49.  
  50. #define WAIT_SEMAPHORE    2
  51. #define SIGNAL_SEMAPHORE  3
  52. #define CLOSE_SEMAPHORE   4
  53.  
  54. // Sorry this test routine is pretty lame but it sort of gets
  55. // the point across
  56.  
  57. #ifdef FT_TEST
  58.  
  59.   #define INITIAL_SEMAPHORE_VALUE     2
  60.   #define WAIT_SECONDS                1
  61.  
  62.   function main()
  63.      local nInitVal, nRc, nHandle, nValue, nOpenCnt
  64.  
  65.      cls
  66.  
  67.      nInitVal := INITIAL_SEMAPHORE_VALUE
  68.      FT_NWSEMOPEN( "TEST", nInitVal, @nHandle, @nOpenCnt )
  69.  
  70.      qout( "Waiting ten seconds..." )
  71.      nRc := ft_nwSemWait( nHandle, 180 )
  72.      qout( "Final nRc value = " + STR( nRc ) )
  73.      inkey(0)
  74.      if nRc == 254
  75.         qout("Couldn't get the semaphore.  Try again.")
  76.         quit
  77.      end
  78.  
  79.      cls
  80.  
  81.      @ 24, 0 say "Any key to exit"
  82.      @ 0,  0 say "Handle: " + str( nHandle )
  83.  
  84.      ft_nwSemEx( nHandle, @nValue, @nOpenCnt )
  85.      while .t.
  86.         @ 23, 0 say "Semaphore test -> Open at [" + ;
  87.                     alltrim(str(nOpenCnt))        + ;
  88.                     "] stations, value is ["      + ;
  89.                     alltrim(str(nValue)) + "]"
  90.  
  91.         if inkey( WAIT_SECONDS ) != 0
  92.            exit
  93.         endif
  94.  
  95.         tone( nHandle,.5 )
  96.         ft_nwSemEx( nHandle, @nValue, @nOpenCnt )
  97.      end
  98.  
  99.      qout( "Signal returns: " + str( ft_nwsemSig( nHandle ) ) )
  100.      qout( "Close returns:  " + str( ft_nwsemClose( nHandle ) ) )
  101.  
  102.   return nil
  103.  
  104. #endif
  105.  
  106.  
  107. /*  $DOC$
  108.  *  $FUNCNAME$
  109.  *      FT_NWSEMOPEN()
  110.  *  $CATEGORY$
  111.  *      NetWare
  112.  *  $ONELINER$
  113.  *      Open or create a NetWare semaphore
  114.  *  $SYNTAX$
  115.  *      FT_NWSEMOPEN( <cName>, <nInitVal>, <@nHandle>, <@nOpenCnt> ) -> nRc
  116.  *  $ARGUMENTS$
  117.  *      <cName> is the semaphore name, maximum length is 127 characters.
  118.  *
  119.  *      <nInitVal> is the initial value for the semaphore.  It must start
  120.  *      as a positive number, to a maximum of 127.
  121.  *
  122.  *      <@nHandle> is the semaphore handle.  THIS MUST BE PASSED BY 
  123.  *      REFERENCE!  On exit, <nHandle> will contain a numeric value that
  124.  *      refers to the opened semaphore.  You will need it to pass to 
  125.  *      other semaphore functions!  PASS IT BY REFERENCE!
  126.  *
  127.  *      <@nOpenCnt> is the number of stations that have opened the 
  128.  *      semaphore.  THIS MUST BE PASSED BY REFERENCE! On exit, <nOpenCnt>
  129.  *      will contain a numeric value.
  130.  *  $RETURNS$
  131.  *      nRc, a numeric result code, as follows:
  132.  *
  133.  *            0 - success
  134.  *          254 - Invalid semaphore name length
  135.  *          255 - Invalid semaphore value
  136.  *     
  137.  *      <nHandle> will contain the semaphore handle, and 
  138.  *      <nOpenCnt> will contain the number of stations that have opened
  139.  *      the semaphore.
  140.  *  $DESCRIPTION$
  141.  *      A semaphore is simply a label that indirectly controls network
  142.  *      activity.  There is a semaphore name, which can be up to 127
  143.  *      characters, and an associated value, which can range from 0 to
  144.  *      127.
  145.  *
  146.  *      A semaphore can be used for many things, but is most often used
  147.  *      to limit the number of users in an application, and to control
  148.  *      access to a network resource.
  149.  *
  150.  *      A semaphore essentially allows you to place locks on resources
  151.  *      other than files.  
  152.  *
  153.  *      An application begins the process by calling FT_NWSEMOPEN().
  154.  *      If the semaphore doesn't exist, NetWare will create it.  
  155.  *      FT_NWSEMOPEN() returns a handle that is used in other semaphore
  156.  *      calls.
  157.  *
  158.  *      Applications use FT_NWSEMWAIT() to wait for a semaphore to 
  159.  *      become available.  FT_NWSEMWAIT() decrements the semaphore's
  160.  *      value by 1.  If the value > 0, then the application should 
  161.  *      be allowed to access the semaphore's resource.  If the value 
  162.  *      goes negative, then the application is placed in a queue.
  163.  *      How long your app is in the queue is determined by how you 
  164.  *      set the timeout parameter.  If you can't get the resource in 
  165.  *      the time you allot, you're let out of the queue and the 
  166.  *      value increments by 1 again.
  167.  *
  168.  *      When an application finishes with a semaphore, it should 
  169.  *      call FT_NWSEMSIG() to increment the value, and then 
  170.  *      FT_NWSEMCLOSE() to close the semaphore.  When the semaphore's
  171.  *      open count goes to 0, NetWare deletes it.
  172.  *
  173.  *      FT_NWSEMEX() can be used to examine the value and open count
  174.  *      without affecting them.
  175.  *
  176.  *      For an interesting discussion on the operating system aspects
  177.  *      of semaphores, check "Operating Systems Design and Implementation"
  178.  *      by A. Tanenbaum, page 60.  For more details on NetWare's 
  179.  *      semaphore facilities, refer to Charles Rose's "Programmer's 
  180.  *      Guide to NetWare".  The "Programmer's Guide" will make an 
  181.  *      excellent companion guide to the source code for all NetWare
  182.  *      functions in the Nanforum Toolkit.
  183.  *  $EXAMPLES$
  184.  *      LOCAL nInitVal, nRc, nHandle, nOpenCnt
  185.  *
  186.  *      nInitVal := 2
  187.  *      nRc      := FT_NWSEMOPEN( "Semaphore Test", nInitVal, ;
  188.  *                                @nHandle, @nOpenCnt )
  189.  *
  190.  *      IF nRc != 0
  191.  *        QOUT =: "Error: " + STR( nRc ) )
  192.  *        QUIT
  193.  *      ENDIF
  194.  *  $SEEALSO$
  195.  *      FT_NWSEMEX() FT_NWSEMWAIT() FT_NWSEMSIG() FT_NWSEMCLOSE() FT_NWSEMLOCK()
  196.  *  $END$
  197.  */
  198.  
  199. function ft_nwSemOpen( cName, nInitVal, nHandle, nOpenCnt )
  200.   local aRegs[ INT86_MAX_REGS ], cRequest, nRet
  201.  
  202.   default cName    to "",   ;
  203.           nInitVal to 0,    ;
  204.           nHandle  to 0,    ;
  205.           nOpenCnt to 0
  206.  
  207.  
  208.   cName    := iif( len( cName ) > 127, substr( cName, 1, 127 ), cName )
  209.   cRequest := chr( len( cName ) ) + cName
  210.  
  211.   aRegs[ AX ]      := makehi( 197 )                       // C5h
  212.   aRegs[ DS ]      := cRequest
  213.   aRegs[ DX ]      := REG_DS
  214.   aRegs[ CX ]      := nInitVal
  215.  
  216.   ft_int86( INT21, aRegs )
  217.  
  218.   nHandle  := bin2l( i2bin( aRegs[CX] ) + i2bin( aRegs[DX] ) )
  219.   nOpenCnt := lowbyte( aRegs[ BX ] )
  220.  
  221.   nRet := lowbyte( aRegs[AX] )
  222.  
  223.   return iif( nRet < 0, nRet + 256, nRet )
  224.  
  225.  
  226.  
  227.  
  228. /*  $DOC$
  229.  *  $FUNCNAME$
  230.  *      FT_NWSEMEX()
  231.  *  $CATEGORY$
  232.  *      NetWare
  233.  *  $ONELINER$
  234.  *      Examine a NetWare semaphore's value and open count
  235.  *  $SYNTAX$
  236.  *      FT_NWSEMEX( <nHandle>, <@nValue>, <@nOpenCnt> ) -> nRc
  237.  *  $ARGUMENTS$
  238.  *      <nHandle> is the semaphore handle, returned from a previous call
  239.  *      to FT_NWSEMOPEN().
  240.  *
  241.  *      <@nValue> will get the current semaphore value.  THIS NUMERIC
  242.  *      ARGUMENT MUST BE PASSED BY REFERENCE!
  243.  *
  244.  *      <@nOpenCnt> will get the current number of workstations 
  245.  *      that have opened the semaphore.  THIS NUMERIC ARGUMENT MUST BE
  246.  *      PASSED BY REFERENCE!
  247.  *  $RETURNS$
  248.  *      nRc, a numeric, as follows:
  249.  *
  250.  *            0 - success
  251.  *          25